﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;

namespace GingerGL.IO
{
    //----------------------------------------------------------------//
    /// <summary>
    /// Zip File System Class
    /// </summary>
    public class ZipFileSystem : IFileSystem
    {
        //------------------------------------------------------------//
        #region Variables
        private ZipFile m_zipfile = null;
        private string[] m_directories;
        private string[] m_files;
        #endregion
        //------------------------------------------------------------//
        #region Properties

        #endregion
        //------------------------------------------------------------//
        #region Constructors
        /// <summary>
        /// Initailizes a new instance of object
        /// </summary>
        public ZipFileSystem(string zipfile)
        {
            if (!File.Exists(zipfile))
            {
                throw new FileNotFoundException(zipfile);
            }

            m_zipfile = new ZipFile(zipfile);
            m_files = new string[m_zipfile.Count];
            m_directories = new string[m_zipfile.Count];

            int ndex = 0;
            foreach (ZipEntry entry in m_zipfile)
            {
                string filepath = Path.Unify(entry.Name);

                m_directories[ndex] = Path.GetFolder(filepath);
                m_files[ndex] = Path.GetFileName(filepath);
                ndex++;
            }
        }
        #endregion
        //------------------------------------------------------------//
        #region Methods
        /// <summary>
        /// Opens a File Streams
        /// </summary>
        public Stream Open(string filename)
        {
            if (!Exists(filename))
            {
                throw new FileNotFoundException(GetFullPath(filename));
            }

            ZipEntry entry = m_zipfile.GetEntry(filename);
            Stream stream = m_zipfile.GetInputStream(entry);

            byte[] buffer = new byte[entry.Size];

            int offset = 0;
            int bytes = 0;

            bytes = stream.Read(buffer, offset, (int)entry.Size);
            offset += bytes;

            if (offset != entry.Size)
                throw new FileLoadException(GetFullPath(filename));

            MemoryStream mem = new MemoryStream(buffer, false);

            return mem;
        }
        /// <summary>
        /// Returns TRUE if file exists
        /// </summary>
        public bool Exists(string filename)
        {
            return m_zipfile.GetEntry(filename) != null;
        }
        /// <summary>
        /// Gets Full Path of File
        /// </summary>
        public string GetFullPath(string filename)
        {
            return Path.Merge(m_zipfile.Name, filename);
        }
        /// <summary>
        /// Gets a list of files
        /// </summary>
        public string[] GetFiles(string path)
        {
            ArrayList list = new ArrayList();
            bool dir_found = false;

            for (int ndex = 0; ndex < m_directories.Length; ndex++)
            {
                if (m_directories[ndex].Equals(path))
                {
                    list.Add(Path.Merge(path, m_files[ndex]));
                    dir_found = true;
                }
            }

            if (!dir_found)
                throw new DirectoryNotFoundException("Directory not found: " + path);

            return (string[])list.ToArray(typeof(string));
        }
        /// <summary>
        /// Gets a list of files
        /// </summary>
        public string[] GetFiles(string path, string pattern)
        {
            return Path.Match(GetFiles(path), pattern);
        }
        /// <summary>
        /// Gets a list of directories
        /// </summary>
        public string[] GetDirectories(string path)
        {
            return Path.Match(m_directories, path + "/*");
        }
        /// <summary>
        /// Gets a list of directories
        /// </summary>
        public string[] GetDirectories(string path, string pattern)
        {
            return Path.Match(m_directories, path + "/" + pattern);
        }
        #endregion
        //------------------------------------------------------------//
    }
    //----------------------------------------------------------------//
}
